#lang racket

(require 2htdp/universe 2htdp/image)

(provide (all-defined-out))

(require "image.rkt")
;............................. Class Animation% ........................................
;Class mère des animations
(define Animation%
(class object%
; Attribut : duree (Durée de l'animation en tick d'horloge), rest (nombre de tick que l'animation devra jouer)
;isWorking (si l'animation joue ou pas), img (l'image relier à l'animation), img-ini (l'image initiale pour le reset)
(init-field (duree 3) (rest 3) )
(init-field (isFinished #f))
(define img-ini (new Image%))
(init-field (img (new Image%)))
(define isWorking '#f)

;(define img (make-object Image% img-ini))

;..................Accesseurs..........................

(define/public (getDuree) duree) ;Renvoi la durée de l'animation
(define/public (getRest) rest);Renvoi le temps restant de l'animation
(define/public (isWorking?) isWorking) ;Renvoi si elle joue
(define/public (getPosX) (send img getPosX)) ;Renvoi la position sur l'axe des abscisses
(define/public (getPosY) (send img getPosY));Renvoi la position sur l'axe des ordonnées
(define/public (getImg-ini) img-ini);Renvoie l'image initiale
(define/public (getImg) img);Renvoie l'image sur laquelle travaille l'animation
(define/public (getClass) 'Animation%);Renvoie la class
(define/public (isFinished?) isFinished)

;.................Mutateurs..................

(define/public (setDuree d) (begin (set! duree d) (set! rest d)));Initialise la durée et donc le temps restant
(define/public (work) (set! isWorking '#t));L'animation est en fonctionnement
(define/public (stop) (set! isWorking '#f) (send img set-isAnimated #f));L'animation s'arrète
(define/public (setRest r) (set! rest r) );Modifie le temps restant
(define/public (setImg-ini imag) (set! img-ini imag) );Initialise l'image initiale
;(define/public (setImg imag) (set! img (make-object (send imag getClass) (send imag getAll)) ))
(define/public (setImg imag) (set! img imag) );Initialise l'image
(define/public (set-isFinished bool) (set! isFinished bool))

;................Méthode jouer()...........
(define/public (jouer)
;Si l'animation joue et que ce n'est pas son dernier tour
(cond [(and isWorking (> rest 1)) (set! rest (- rest 1))]
;Si l'animation joue et que c'est pas son dernier tour
[(and isWorking (= rest 1)) (begin (set! isWorking '#f) (set! rest duree))]
;Si l'animation ne joue pas
[(not isWorking) (begin (set! isWorking '#t) (set! rest (- rest 1)))]
[else (error "wrong")]
))

;................Méthode toString().............
(define/public (toString)
(format "<[ ~a | duree ~a | rest ~a | finished ~a ]>"
(send this getClass)
(send this getDuree)
(send this getRest)
(send this isFinished?)))

(super-new)
)
)

; ....................................... Class Animation-changer-couleur% ...................................
;Class qui change la couleur d'une image
(define Animation-changer-couleur%
(class Animation%
;(init-field (duree 0) (rest 0) )
(init-field (couleurs-disponibles (list "red" "green" "blue" "purple" "yellow")))

;..................Accesseurs..........................
(define/override (getClass) 'Animation-changer-couleur%);Renvoie la class

;................Méthode jouer()...........
(define/override (jouer)
;Si l'animation est en fonctionnement et qu'il lui reste plus d'un tour à jouer on décrémente le compteur de 1
(cond [(and (send this isWorking?) (> (send this getRest) 1)) (send this setRest (- (send this getRest) 1))]
;Si l'animation est en fonctionnement et que c'est son dernier tour de jeu, l'animation est finie.
[(and (send this isWorking?) (= (send this getRest) 1)) (begin
(send this stop)
(send this set-isFinished #t))]
;Si l'animation n'est pas en fonctionnement elle démarre, le reste est décrémenté de 1 et l'image prend la
;couleur choisi
[(not (send this isWorking?)) (begin
(printf "animation not working")
(send this work)
(send this setRest (- (send this getRest) 1))
[send (send this getImg) setCouleur (list-ref couleurs-disponibles (random (length couleurs-disponibles))) ] )]
;Sinon il y a une érreur
[else (error "Problème de durée")]
))

(super-new)
)
)

; ....................................... Class Animation-lever% ...................................
;Class qui fait osciller une image
(define Animation-lever%
(class Animation%
;(init-field (duree 0) (rest 0) )

;..................Accesseurs..........................
(define/override (getClass) 'Animation-lever%)

;................Méthode jouer()...........
(define/override (jouer) ; On part sur une lever de 20 sur l'axe des y
(define image (send this getImg))
(define lever 40)
;Si l'animation est en fonctionnement et qu'il lui reste plus d'un tour à jouer
(cond [(and (send this isWorking?) (> (send this getRest) 1))
;Si le reste est >= à 2/3 de la durée
(begin (if (>= (send this getRest) (* 2 (/ (send this getDuree) 3)) )
;On leve l'image de (lever/(la durée / 3))
(send image setPosY [- (send image getPosY) (/ lever (/ (send this getDuree) 3) ) ])
;Sinon on baisse l'image de (lever/(2(la durée / 3)))
(send image setPosY [+ (send image getPosY) (/ lever (* 2 (/ (send this getDuree) 3)) ) ]) )
;On décrémente le reste de 1
(send this setRest (- (send this getRest) 1))
)]
;Si l'animation est en fonctionnement et que c'est son dernier tour de jeu, le reste est réinitialisé à la
;durée initiale et l'image reprend sa position d'origine
[(and (send this isWorking?) (= (send this getRest) 1)) (begin (send this stop) (send this set-isFinished #t) [send image setPosY (send (send this getImg-ini) getPosY)] )]
;Si l'animation n'est pas en fonctionnement elle démarre se
;lève de (lever/(la durée / 3))
[(not (send this isWorking?)) (begin (send this work) (send this setRest (- (send this getRest) 1)) (send image setPosY [- (send image getPosY) (/ lever (* 2 (/ (send this getDuree) 3)) ) ]) )]
;Sinon Erreur
[else (error "Problème de durée")]
))

(super-new)
)
)

; ....................................... Class Animation-basse% ...................................
;Class qui fonctionne avec une Image% : Balle% et qui fait varier le diamètre de celle-ci
(define Animation-basse%
(class Animation%
;(init-field (duree 0) (rest 0) )
  
  ;..................Accesseurs..........................
(define/override (getClass) 'Animation-basse%)
  
  
(define/override (jouer)
  (define image (send this getImg))
  (define rayon (send (send this getImg-ini) getRayon))
  
;Si l'animation est en fonctionnement et qu'il lui reste plus d'un tour à jouer
(cond [(and (send this isWorking?) (> (send this getRest) 1))
;Si le reste est >= à 2/3 de la durée       
(begin (if (>= (send this getRest) (* 2 (/ (send this getDuree) 3)) )
           ;On augmente le rayon de l'image de sont rayon + (son rayon d'origine /10) / (1/3)de la durée
           (begin (send image setRayon (+ (send image getRayon) (/ (/ rayon 10) (/ (send this getDuree) 3))))
                  ;On modifie x et y en conséquence pour que le centre du cercle garde la même position
                  (send image setPosY [- (send image getPosY) (/ (/ rayon 10) (/ (send this getDuree) 3)) ])
                  (send image setPosX [- (send image getPosX) (/ (/ rayon 10) (/ (send this getDuree) 3)) ]))
           ;On diminue le rayon de l'image de sont rayon - (son rayon d'origine /10) / (2/3)de la durée
           (begin (send image setRayon (- (send image getRayon) (/ (/ rayon 10) (* 2 (/ (send this getDuree) 3)))))
                  ;On modifie x et y en conséquence pour que le centre du cercle garde la même position
                  (send image setPosY [+ (send image getPosY) (/ (/ rayon 10) (* 2 (/ (send this getDuree) 3))) ])
                  (send image setPosX [+ (send image getPosX) (/ (/ rayon 10) (* 2 (/ (send this getDuree) 3))) ])))
;On décrémente le reste de 1
(send this setRest (- (send this getRest) 1)))
]
           
;Si l'animation est en fonctionnement et que c'est son dernier tour de jeu,     
[(and (send this isWorking?) (= (send this getRest) 1)) (begin (send this stop) (send this set-isFinished #t) (send this setRest (send this getDuree)) (send image setRayon rayon) (send image setPosX (send (send this getImg-ini) getPosX))  (send image setPosY (send (send this getImg-ini) getPosY))  )]
;Si l'animation n'est pas en fonctionnement elle démarre et modifie son rayon etc
[(not (send this isWorking?)) (begin (send this work) (send this setRest (- (send this getRest) 1)) (send image setRayon (+ rayon (/ (/ rayon 10) (/ (send this getDuree) 3)))) (send image setPosY [- (send image getPosY) (/ (/ rayon 10) (/ (send this getDuree) 3)) ]) (send image setPosX [- (send image getPosX) (/ (/ rayon 10) (/ (send this getDuree) 3)) ]) )]
;Sinon Erreur
[else (error "Problème de durée")]
))

(super-new)
)
)

;(define A (circle 30 'solid "red"))

